package es.udc.acs.database.operations;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import es.udc.acs.database.Database;
import es.udc.acs.database.exception.ConexionInvalidaException;
import es.udc.acs.consorcio.mensaje.Mensaje;
import es.udc.acs.consorcio.sesion.Sesion;


public class DBConsorcioOperations {	
	
	
	private static ByteArrayOutputStream convertirBytes(Object objeto) 
			throws IOException {
	 
		ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(byteArray);
		oos.writeObject(objeto);
	
		return byteArray;
	}

	
	public static void crearSesionConsorcio(String idBanco,
											Sesion sesion) 
											throws SQLException, 
												   IOException {
		
		
	    Connection conexion = Database.getInstancia().getConexion();

	    if (conexion!=null) {
	    	
			PreparedStatement ps = 
					conexion.prepareStatement(
							"INSERT INTO c_sesion values (? , ?)");
	
			ByteArrayOutputStream byteArray = convertirBytes(sesion); 
			
			// Se inserta en bd
			ps.setString(1, idBanco);
			ps.setBytes(2, byteArray.toByteArray());
			ps.execute();
		
	    }
	}
	
	public static void eliminarSesionConsorcio(String idBanco) {
		
	    Connection conexion = Database.getInstancia().getConexion();

	    if (conexion!=null) {
	    	
			PreparedStatement ps;
			try {
				ps = conexion.prepareStatement(
						"DELETE FROM c_sesion WHERE id_banco = ?");
				
				// Se inserta en bd
				ps.setString(1, idBanco);
				ps.execute();
			} catch (SQLException e) {}		
	    }
	}	
	
	public static void guardarSesionConsorcio(String idBanco,
			                                  Sesion sesion) 
			                                  throws SQLException, 
				                                     IOException, 
				                                     ConexionInvalidaException {
		
		
		Connection conexion = Database.getInstancia().getConexion();
		
		if (conexion!=null) {
		
			PreparedStatement ps = 
			conexion.prepareStatement(
			"UPDATE c_sesion SET obj_sesion = ? WHERE id_banco = ?");
			
			ByteArrayOutputStream byteArray = convertirBytes(sesion); 
			
			// Se inserta en bd
			ps.setBytes(1, byteArray.toByteArray());
			ps.setString(2, idBanco);
			ps.execute();
		
		} else {
			throw new ConexionInvalidaException();
		}
		
	}
	
	
	public static Sesion obtenerSesionConsorcio(String idBanco) throws SQLException {
			
		    Connection conexion = Database.getInstancia().getConexion();
		    
		    String sentencia = "SELECT id_banco,obj_sesion " +
		    				   "FROM c_sesion " +
		    		           "WHERE id_banco = '"+idBanco+"'";
	
		    if (conexion!=null) {	    	
		    
				Statement stmt   = conexion.createStatement();
		        ResultSet result = stmt.executeQuery(sentencia);	        
		        
		        try {
					result.next();				
					Blob blob = result.getBlob("obj_sesion");
	
				   // Se reconstruye el objeto con un ObjectInputStream
				   ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
				   Sesion sesion = (Sesion) ois.readObject();
			        
				   return sesion;
				   
				} // result.next() falla porque no hay datos
				catch (Exception e) {
					return null;
				}    
		    }
		    
		    return null;
	}
	
	
	public static boolean existeSesionConsorcio(String idBanco) 
												throws SQLException {
		
	    Connection conexion = Database.getInstancia().getConexion();
	    
	    String sentencia = "SELECT id_banco " +
	    				   "FROM c_sesion " +
	    		           "WHERE id_banco = '"+idBanco+"'";

	    if (conexion!=null) {	    	
	    
			Statement stmt   = conexion.createStatement();
	        ResultSet result = stmt.executeQuery(sentencia);	        
	        
	        try {
				result.next();				
				result.getString(1);
		        
			   return true;
			   
			} // result.next() falla porque no hay datos
			catch (Exception e) {
				return false;
			}    
	    }
	    
	    return false;
}
	
	
	public static int crearMensajeConsorcio(String idBanco,
			                                int idTarjeta,
			                                Mensaje mensaje, 
			                                int importe,
			                                int estado) 
			                                throws SQLException, 
			                                       IOException, 
			                                       ConexionInvalidaException {		
	
		
	    Connection conexion = Database.getInstancia().getConexion();	
		
	    comprobarBanco(idBanco);
	    int numMensaje = obtenerUltimoMensaje(idBanco, idTarjeta);		
	
	    if (conexion!=null) {
	    
			PreparedStatement ps = 
					conexion.prepareStatement(
				     "INSERT INTO c_mensaje values (? , ? , ? , ? , ? , ?)");
	
			mensaje.setIdMensaje(numMensaje);
			ByteArrayOutputStream byteArray = convertirBytes(mensaje); 
			
			// Se inserta en bd
			ps.setString(1, idBanco);
			ps.setInt(2, idTarjeta);
			ps.setInt(3, numMensaje);
			ps.setInt(4, importe);
			ps.setBytes(5, byteArray.toByteArray());
			ps.setInt(6, estado);
			ps.execute();
		
			return numMensaje;
		} else {
			throw new ConexionInvalidaException();
		}
	}
	
	private static void comprobarBanco(String idBanco) 
			                           throws ConexionInvalidaException {
		
	    Connection conexion = Database.getInstancia().getConexion();

	    if (conexion!=null) {
	    
	    	try {
				PreparedStatement ps = conexion.prepareStatement(
						"INSERT INTO c_sesion values (? , null)");		
				
				ps.setString(1, idBanco);
				ps.execute();
	    	} catch (Exception e) {
	    		// Sino inserta es que ya esta por lo que no es necesario hacer nada
	    	}
		
		} else {
			throw new ConexionInvalidaException();
		}
	}
	
	
	private static int obtenerUltimoMensaje(String idBanco ,
											int idTarjeta) 
											throws SQLException {
		
	    Connection conexion = Database.getInstancia().getConexion();
		
		// obtenemos el número del último mensaje guardado
	    String obtenerUmen = "SELECT max(id_mensaje) " 
	    	                 +"FROM c_mensaje " 
	    	                 +"WHERE id_banco = '"+idBanco+"' " 
	    	                 +"AND id_tarjeta = "+idTarjeta;
	    
		int it = 0;
		
		if (conexion != null) {
			
			Statement stmt   = conexion.createStatement();
	        ResultSet result = stmt.executeQuery(obtenerUmen);	
	        // si hubo alguno antes
	        try {
		        result.next();	        
		        it = result.getInt(1)+1;     	        
	        } catch (Exception e) {}
	        stmt.close();        
		}
		
		return it;
	}
	
	
	/**
	 * Actualiza un mensaje despues de ser enviado para pasar a modo procesado
	 */
	public static void actualizarMensajeConsorcio(String idBanco,
										          int idTarjeta,
										          int idMensaje,
										          Mensaje mensaje) 
										          throws SQLException, 
										                 IOException, 
										                 ConexionInvalidaException {		
	
		Connection conexion = Database.getInstancia().getConexion();	
		
		if (conexion!=null) {
		
			PreparedStatement ps = 
			conexion.prepareStatement(
			      "UPDATE c_mensaje SET obj_mensaje = ?, procesado = 1 "
			      +"WHERE id_banco = ? " 
			      +"AND id_tarjeta = ? " 
			      +"AND id_mensaje = ? ");
			
			ByteArrayOutputStream byteArray = convertirBytes(mensaje); 
			
			// Se inserta en bd
			ps.setBytes(1, byteArray.toByteArray());
			ps.setString(2, idBanco);
			ps.setInt(3, idTarjeta);
			ps.setInt(4, idMensaje);
			ps.execute();
		
		} else {
			throw new ConexionInvalidaException();
		}
	}
	
	
	/**
	 * Comprueba que los mensajes offline de una tarjeta no superen
	 * el importe maximo
	 */
	public static boolean comprobarImporteTarjeta(String idBanco,
			                                      int idTarjeta,
			                                      int importe) 
            							          throws ConexionInvalidaException, 
            							                 SQLException {

		Connection conexion = Database.getInstancia().getConexion();
		
		if (conexion!=null) {	

			PreparedStatement ps = 
					conexion.prepareStatement(
						"SELECT SUM(importe) " 
						+"FROM c_mensaje " 
						+"WHERE (id_banco = ?) " 
						+"AND (id_tarjeta = ?) " 
						+"AND (procesado = 0)");		

			ps.setString(1, idBanco);
			ps.setInt(2, idTarjeta);
			ResultSet rs = ps.executeQuery();
			
			try {
				while (rs.next()) {					
					int importeOperaciones = rs.getInt(1);
					
					return ((importe+importeOperaciones) <= 1000);		        		
		        }
			}catch (Exception e) {
				// si falla es porque no hay ningun mensaje
			}
			
			return true;
			
		} else {
			throw new ConexionInvalidaException();
		}
	}


	/**
	 * Elimina los mensajes y las sesiones guardadas en la BD
	 */
	public static void borrarConsorcioDB() throws ConexionInvalidaException, 
	                                              SQLException {
		
		Connection conexion = Database.getInstancia().getConexion();
		
		if (conexion!=null) {	

			borrarLogsConsorcio(conexion);
			borrarMensajesConsorcio(conexion);
			borrarSesionesConsorcio(conexion);
			
		} else {	    
			throw new ConexionInvalidaException();
		}
		
	}
	
	private static void borrarSesionesConsorcio(Connection conexion) 
		                                       throws SQLException {						

		
		PreparedStatement ps = conexion.prepareStatement("DELETE FROM c_sesion");
		ps.execute();
	}	
	
	private static void borrarMensajesConsorcio(Connection conexion) 
                                                throws SQLException {						


		PreparedStatement ps = conexion.prepareStatement("DELETE FROM c_mensaje");
		ps.execute();
	}	
	
	private static void borrarLogsConsorcio(Connection conexion) 
										    throws SQLException {						

	
		PreparedStatement ps = conexion.prepareStatement("DELETE FROM c_log");
		ps.execute();
	}	
	
	/**
	 * inserta un log en la tabla de logs
	 */
	public static void insertarLog(String mensaje) 
                                   throws SQLException, 
                                          ConexionInvalidaException {
		
		Connection conexion = Database.getInstancia().getConexion();

		int nlog = obtenerNLog();
		
		String sentencia = 
	    "INSERT INTO c_log "+
	    "VALUES ("+nlog+",'"+mensaje+"',"
	    		+"(SELECT sysdate FROM dual))";
		
		
		if (conexion != null) {
			
			Statement stmt = conexion.createStatement();
			stmt.executeUpdate(sentencia);			
			stmt.close();			
		} else 
			throw new ConexionInvalidaException();
	}
	
	/**
	 * Obtiene el numero del ultimo log de esa cuenta
	 */
	private static int obtenerNLog() 
                                   throws SQLException {
		
		// obtenemos el número del último log guardado
        String obtenerNlog = "SELECT max(id_clog) " +
        	                 "FROM c_log ";
        
		Connection conexion = Database.getInstancia().getConexion();
		int nlog = 0;
		
		if (conexion != null) {
			
			Statement stmt   = conexion.createStatement();
	        ResultSet result = stmt.executeQuery(obtenerNlog);	
	        // si hubo alguno antes
	        try {
		        result.next();	        
		        nlog = result.getInt(1)+1;     	        
	        } catch (Exception e) {}
	        
	        stmt.close();        
		}
		
		return nlog;
	}	
}
